17.1 概述

按官方说法,Go GC的基本特征是“非分代、非紧缩、写屏障、并发标记清理”。

mgc.go

The GC runs concurrently with mutator threads,is type accurate(aka precise),allows multiple GC thread to run in parallel.It is a concurrent mark and sweep that uses a write barrier.It is non-generational and non-compacting.Allocation is done using size segregated per P allocation areas to minimize fragmentation while eliminating locks in the common case.

The algorithm decomposes into several steps.

该文件头部有GC的详细说明,只有个别地方和源码有些出入,但不影响对算法和过程的理解。

与之前版本在STW状态下完成标记不同,并发标记和用户代码同时执行让一切都处于不稳定状态。用户代码随时可能修改已经被扫描过的区域,在标记过程中还会不断分配新对象,这让垃圾回收变得很麻烦。

究竟什么时候启动垃圾回收?过早会严重浪费CPU资源,影响用户代码执行性能。而太晚,会导致堆内存恶性膨胀。如何正确平衡这些问题就是个巨大的挑战。

所有问题的核心:抑制堆增长,充分利用CPU资源。为此,Go引入一系列举措。

三色标记和写屏障

这是让标记和用户代码并发的基本保障,基本原理:

  • 起初所有对象都是白色。
  • 扫描找出所有可达对象,标记为灰色,放入待处理队列。
  • 从队列提取灰色对象,将其引用对象标记为灰色放入队列,自身标记为黑色。
  • 写屏障监视对象内存修改,重新标色或放回队列。

当完成全部扫描和标记工作后,剩余的不是白色就是黑色,分别代表待回收和活跃对象,清理操作只须将白色对象内存收回即可。

控制器

控制器全程参与并发回收任务,记录相关状态数据,动态调整运行策略,影响并发标记单元的工作模式和数量,平衡CPU资源占用。当回收结束时,参与next_gc回收阈值设置,调整垃圾回收触发频率。

mgc.go

gcController implements the GC pacing controller that determines when to trigger concurrent garbage collection and how much marking work to do in mutator assists and background marking.

It uses a feedback control algorithm to adjust the memstats.next_gc trigger based on the heap growth and GC CPU utilization each cycle.

This algorithm optimizes for heap growth to match GOGC and for CPU utilization between assist and background marking to be 25%of GOMAXPROCS.

The high-level design of this algorithm is documented at https://golang.org/s/go15gcpacing.

辅助回收

某些时候,对象分配速度可能远快于后台标记。这会引发一系列恶果,比如堆恶性扩张,甚至让垃圾回收永远无法完成。

此时,让用户代码线程参与后台回收标记就非常有必要。在为对象分配堆内存时,通过相关策略去执行一定限度的回收操作,平衡分配和回收操作,让进程处于良性状态。